package com.innovate.cms.modules.qs.web.order;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.innovate.cms.common.config.Global;
import com.innovate.cms.common.mapper.JsonMapper;
import com.innovate.cms.common.utils.StrUtil;
import com.innovate.cms.common.utils.StringUtils;
import com.innovate.cms.common.web.BaseController;
import com.innovate.cms.modules.common.entity.BaseBackInfo;
import com.innovate.cms.modules.common.entity.ItemBackInfo;
import com.innovate.cms.modules.qs.entity.msg.DynamicMsgForService;
import com.innovate.cms.modules.qs.entity.order.DbOrder;
import com.innovate.cms.modules.qs.entity.order.WXMyConfigUtil;
import com.innovate.cms.modules.qs.service.msg.DynamicMsgService;
import com.innovate.cms.modules.qs.service.order.DbOrderService;

/**
 * 微信支付
 * 
 * @author shifangfang
 * @date 2018年1月8日 下午6:02:17
 */
@Controller
@RequestMapping(value = "/api/wxpay")
public class WxPayController extends BaseController {

	@Autowired
	private DbOrderService dbOrderService;
	@Autowired
	private DynamicMsgService dynamicMsgService;

	/**
	 * 生成16位订单号
	 * 
	 * @return
	 */
	public static String genTradeNo() {
		int first = new Random().nextInt(8) + 1;
		int hashCodeV = UUID.randomUUID().toString().hashCode();
		if (hashCodeV < 0) {// 有可能是负数
			hashCodeV = -hashCodeV;
		}
		return first + String.format("%015d", hashCodeV);
	}

	@RequestMapping(value = "/pay", method = { RequestMethod.GET, RequestMethod.POST })
	public @ResponseBody BaseBackInfo orderPay(@RequestBody Map<String, String> map, HttpServletRequest req, HttpServletResponse response) throws Exception {
		ItemBackInfo backInfo = new ItemBackInfo();

		String priceStr = map.get("price");
		// 微信支付钱的单位为分
		Double double1 = Double.valueOf(priceStr) * 100;
		String total_fee = double1.intValue() + "";
		String title = map.get("title");
		String user_id = map.get("consumerUid");
		String coupon_id = map.get("mid");
		String mobile = map.get("mobile");
		String num = map.get("num");
		// 首先判断是否过期
		// int consumeState = 1;
		Calendar now = Calendar.getInstance();
		// now.set(Calendar.HOUR_OF_DAY, 23);
		// now.set(Calendar.MINUTE, 59);
		// now.set(Calendar.SECOND, 59);
		// 获取消息详情
		DynamicMsgForService msg = dynamicMsgService.msgInfo(Integer.parseInt(coupon_id));
		// 如果订单有效时间当天，说明已经过期
		if (msg.getMsgEndDate().getTime() < now.getTimeInMillis()) {
			logger.info("消费时间过期,无法消费! mid:" + coupon_id + " title:" + map.get("title"));
			BaseBackInfo info = new BaseBackInfo();
			info.setStateCode(Global.intNO);
			info.setRetMsg("消费时间过期,无法消费!");
			return info;
		}

		if (StrUtil.isBlank(user_id) || StrUtil.isBlank(user_id) || StrUtil.isBlank(coupon_id) || StrUtil.isBlank(title)) {
			BaseBackInfo info = new BaseBackInfo();
			info.setStateCode(Global.int300209);
			info.setRetMsg(Global.str300209);
			return info;
		}
		DbOrder dbOrder = new DbOrder();

		String out_trade_no = genTradeNo(); // 777777 需要前端给的参数
		// 生成订单号
		dbOrder.setTradeNo(out_trade_no);
		dbOrder.setConsumerUid(user_id);
		dbOrder.setMobile(mobile);
		dbOrder.setMid(Integer.parseInt(coupon_id));
		dbOrder.setPrice(Double.valueOf(priceStr));
		dbOrder.setNum(Integer.parseInt(num));
		// 微信支付设置为0
		dbOrder.setPayType(0);

		String attach = user_id + "," + coupon_id + "\t" + title;
		WXMyConfigUtil config = new WXMyConfigUtil();
		// String spbill_create_ip = GetIPAddrUtil.getIpAddr(req);
		String spbill_create_ip = StringUtils.getRemoteAddr(req);
		System.err.println(spbill_create_ip);
		String url = req.getRequestURL().toString();
		String notify_url = req.getRequestURL().substring(0, url.lastIndexOf("/")) + "/notify";
		logger.info("notify_url:" + notify_url);

		Map<String, String> result = dounifiedOrder(attach, out_trade_no, total_fee, spbill_create_ip, 1, notify_url);
		String nonce_str = (String) result.get("nonce_str");
		String prepay_id = (String) result.get("prepay_id");
		Long time = System.currentTimeMillis() / 1000;
		String timestamp = time.toString();

		// 签名生成算法
		Map<String, String> mapSign = new HashMap<>();
		mapSign.put("appid", config.getAppID());
		mapSign.put("partnerid", config.getMchID());
		mapSign.put("package", "Sign=WXPay");
		mapSign.put("noncestr", nonce_str);
		mapSign.put("timestamp", timestamp);
		mapSign.put("prepayid", prepay_id);
		String sign = MD5Util.getSign(mapSign);

		// String resultString = "{\"tradeNo\":\"" + out_trade_no +
		// "\",appid\":\"" + config.getAppID() +
		// "\",\"partnerid\":\"" + config.getMchID() +
		// "\",\"package\":\"Sign=WXPay\"," + "\"noncestr\":\""
		// + nonce_str + "\",\"timestamp\":" + timestamp + "," +
		// "\"prepayid\":\"" + prepay_id + "\",\"sign\":\"" +
		// sign + "\"}";

		JSONObject jsonObject = new JSONObject();
		jsonObject.put("tradeNo", out_trade_no);
		jsonObject.put("appid", config.getAppID());
		jsonObject.put("partnerid", config.getMchID());
		jsonObject.put("package", "Sign=WXPay");
		jsonObject.put("noncestr", nonce_str);
		jsonObject.put("timestamp", timestamp);
		jsonObject.put("prepayid", prepay_id);
		jsonObject.put("sign", sign);

		// System.err.println(resultString);
		backInfo.setStateCode(Global.intYES);
		backInfo.setRetMsg(Global.SUCCESS);
		backInfo.setItem(jsonObject);
		// 存储预支付订单
		dbOrderService.saveOrder(dbOrder);

		// 给前端app返回此字符串，再调用前端的微信sdk引起微信支付
		return backInfo;

	}

	public Map<String, String> dounifiedOrder(String attach, String out_trade_no, String total_fee, String spbill_create_ip, int type, String notify_url) throws Exception {
		Map<String, String> fail = new HashMap<>();
		WXMyConfigUtil config = new WXMyConfigUtil();
		WXPay wxpay = new WXPay(config);
		Map<String, String> data = new HashMap<String, String>();
		// data.put("appid", config.getAppID());
		// data.put("mch_id", config.getMchID());
		// data.put("nonce_str",WXPayUtil.generateNonceStr());
		// data.put("nonce_str","6128be982a7f40daa930025dedd1a90d");
		String body = "订单支付";
		data.put("body", body);
		data.put("out_trade_no", out_trade_no);
		data.put("total_fee", total_fee);
		data.put("spbill_create_ip", spbill_create_ip);
		// 异步通知地址（请注意必须是外网）
		data.put("notify_url", notify_url);

		data.put("trade_type", "APP");
		data.put("attach", attach);
		// data.put("sign", md5Util.getSign(data));
		StringBuffer url = new StringBuffer();
		try {
			Map<String, String> resp = wxpay.unifiedOrder(data);
			System.out.println(resp);
			String returnCode = resp.get("return_code"); // 获取返回码
			String returnMsg = resp.get("return_msg");

			if ("SUCCESS".equals(returnCode)) { // 若返回码为SUCCESS，则会返回一个result_code,再对该result_code进行判断
				String resultCode = (String) resp.get("result_code");
				String errCodeDes = (String) resp.get("err_code_des");
				System.out.print(errCodeDes);
				if ("SUCCESS".equals(resultCode)) {
					// 获取预支付交易回话标志
					Map<String, String> map = new HashMap<>();
					String prepay_id = resp.get("prepay_id");
					String signType = "MD5";
					map.put("prepay_id", prepay_id);
					map.put("signType", signType);
					String sign = MD5Util.getSign(map);
					resp.put("realsign", sign);
					url.append("prepay_id=" + prepay_id + "&signType=" + signType + "&sign=" + sign);
					return resp;
				} else {
					logger.info("订单号：{},错误信息：{}", out_trade_no, errCodeDes);
					url.append(errCodeDes);
				}
			} else {
				logger.info("订单号：{},错误信息：{}", out_trade_no, returnMsg);
				url.append(returnMsg);
			}

		} catch (Exception e) {
			System.out.println("aaaaaaaaaaaaa");
			System.out.println(e);
			logger.info(e.getMessage());
		}
		return fail;
	}

	/**
	 * 订单支付异步通知
	 */
	// @ApiOperation(value = "手机订单支付完成后回调")
	@RequestMapping(value = "/notify", method = { RequestMethod.GET, RequestMethod.POST })
	public @ResponseBody BaseBackInfo WXPayBack(HttpServletRequest request, HttpServletResponse response) {
		ItemBackInfo backInfo = new ItemBackInfo();
		String resXml = "";
		System.err.println("进入异步通知");
		try {
			//
			InputStream is = request.getInputStream();
			// 将InputStream转换成String
			BufferedReader reader = new BufferedReader(new InputStreamReader(is));
			StringBuilder sb = new StringBuilder();
			String line = null;
			try {
				while ((line = reader.readLine()) != null) {
					sb.append(line + "\n");
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			resXml = sb.toString();
			System.err.println(resXml);
			String result = payBack(resXml);
			// / return
			// "<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>";
			backInfo.setItem(result);
			return backInfo;
		} catch (Exception e) {
			logger.error("手机支付回调通知失败", e);
			String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
			backInfo.setStateCode(-1);
			backInfo.setRetMsg(result);
			return backInfo;
		}
	}

	/**
	 * 支付结果通知
	 * 
	 * @param notifyData
	 *            异步通知后的XML数据
	 * @return
	 */
	public String payBack(String notifyData) {
		WXMyConfigUtil config = null;
		try {
			config = new WXMyConfigUtil();
		} catch (Exception e) {
			e.printStackTrace();
		}
		WXPay wxpay = new WXPay(config);
		String xmlBack = "";
		Map<String, String> notifyMap = null;
		try {
			notifyMap = WXPayUtil.xmlToMap(notifyData); // 转换成map

			if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
				// 签名正确
				// 进行处理。
				// 注意特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户侧订单状态从退款改成支付成功
				String return_code = notifyMap.get("return_code");// 状态
				String out_trade_no = notifyMap.get("out_trade_no");// 订单号
				// String transactionId = notifyMap.get("transaction_id");//
				// 微信支付订单号

				if (return_code.equals("SUCCESS")) {
					if (out_trade_no != null) {
						// 处理订单逻辑
						/**
						 * 更新数据库中支付状态。
						 * 特殊情况：订单已经退款，但收到了支付结果成功的通知，不应把商户侧订单状态从退款改成支付成功。
						 * 此处需要判断一下。后面写入库操作的时候再写
						 * 
						 */

						System.err.println(">>>>>支付成功");
						// 把预支付订单状态改为成功支付
						// 订单状态
						// 0-预支付订单(微信淘宝的预支付,在没确认回调成功之前的状态)
						// 1-成功支付的订单
						int orderState = 1;
						dbOrderService.updateOrderState(out_trade_no, orderState, JsonMapper.toJsonString(notifyMap));

						logger.info("微信手机支付回调成功订单号:{}", out_trade_no);
						xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
					} else {
						logger.info("微信手机支付回调失败订单号:{}", out_trade_no);
						xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
					}

				}
				return xmlBack;
			} else {
				// 签名错误，如果数据里没有sign字段，也认为是签名错误
				logger.error("手机支付回调通知签名错误");
				xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
				return xmlBack;
			}
		} catch (Exception e) {
			logger.error("手机支付回调通知失败", e);
			xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
		}
		return xmlBack;
	}

}
